Skip to content

fix(evm): skip JUMPDEST skip-cost metering when in dead code#365

Open
starwarfan wants to merge 1 commit intoDTVMStack:mainfrom
starwarfan:fix-jumpdest-dead-code-metering
Open

fix(evm): skip JUMPDEST skip-cost metering when in dead code#365
starwarfan wants to merge 1 commit intoDTVMStack:mainfrom
starwarfan:fix-jumpdest-dead-code-metering

Conversation

@starwarfan
Copy link
Contributor

When a consecutive JUMPDEST run follows dead code (e.g., after an unconditional JUMP), meterOpcodeRange was called while CurBB was already terminated. This appended gas-metering instructions (including a BrIfInstruction terminator) after the existing terminator, creating a basic block with two terminators. LLVM's MC assembler then emitted a branch to the ContinueBB label but never defined it (the block was unreachable), producing Undefined temporary symbol .LBB0_43.

Fix: Guard the meterOpcodeRange call with !InDeadCode. When execution reaches a JUMPDEST via an indirect jump, the per-target entry thunks already charge the correct skip cost, so the linear-path metering is unnecessary and incorrect in the dead-code case.

1. Does this PR affect any open issues?(Y/N) and add issue references (e.g. "fix #123", "re #123".):

  • N
  • Y

2. What is the scope of this PR (e.g. component or file name):

src/action/evm_bytecode_visitor.h

3. Provide a description of the PR(e.g. more details, effects, motivations or doc link):

  • Affects user behaviors
  • Contains CI/CD configuration changes
  • Contains documentation changes
  • Contains experimental features
  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Other

The bytecode visitor merges consecutive JUMPDEST opcodes into a single run and calls meterOpcodeRange to charge the skip cost for the JUMPDESTs that the linear decode skips over. However, when the JUMPDEST run is preceded by dead code (e.g., after a JUMP or STOP), CurBB is still the terminated block from the previous control-flow instruction.

Calling meterGas inside meterOpcodeRange appends a gas-check branch (BrIfInstruction) plus a new ContinueBB to the already-terminated CurBB. This produces a basic block with two terminators. LLVM drops the unreachable ContinueBB during codegen but still emits a branch reference to its label, causing the MC assembler error Undefined temporary symbol .LBB0_43.

The fix is safe because indirect jumps landing on a merged JUMPDEST already go through per-target entry thunks (created in createJumpTable) that charge the exact skip cost. The linear-path meterOpcodeRange is only needed for fall-through, which cannot happen when InDeadCode is true.

4. Are there any breaking changes?(Y/N) and describe the breaking changes(e.g. more details, motivations or doc link):

  • N
  • Y

5. Provide a description of the tests:

Verified with crash-bf1bdbf1 (the crash file that triggered Undefined temporary symbol .LBB0_43) using evmone-fuzzer in multipass mode. All 7 remaining crash files in fuzz_output/ pass after the fix. Code format check (./tools/format.sh format) passes.

Made with Cursor

When a consecutive JUMPDEST run follows dead code (e.g., after an
unconditional JUMP), meterOpcodeRange was called while CurBB was
already terminated. This appended gas-metering instructions (including
a BrIfInstruction terminator) after the existing terminator, creating
a basic block with two terminators.  LLVM's MC assembler then emitted
a branch to the ContinueBB label but never defined it (the block was
unreachable), producing "Undefined temporary symbol .LBB0_43".

Guard the meterOpcodeRange call with !InDeadCode.  When execution
reaches a JUMPDEST via an indirect jump, the per-target entry thunks
already charge the correct skip cost, so the linear-path metering is
unnecessary and incorrect in the dead-code case.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant